package ru.ifmo.genetics.adaptation;

import org.uncommons.watchmaker.framework.*;
import org.uncommons.watchmaker.framework.interactive.InteractiveSelection;

import java.util.*;

/**
 * @author Roman Kolganov
 *         10.12.11
 */
public class GenerationalAdaptingEvolutionEngine<T> extends GenerationalEvolutionEngine<T> {

    protected final List<AdaptableParameter<T>> adaptableParameters;
    protected final List<List<EvaluatedCandidate<T>>> lastGenerations = new ArrayList<List<EvaluatedCandidate<T>>>();

    public GenerationalAdaptingEvolutionEngine(CandidateFactory<T> tCandidateFactory,
                                               EvolutionaryOperator<T> evolutionScheme,
                                               FitnessEvaluator<? super T> fitnessEvaluator,
                                               SelectionStrategy<? super T> selectionStrategy,
                                               Random rng,
                                               List<AdaptableParameter<T>> adaptableParameters) {
        super(tCandidateFactory, evolutionScheme, fitnessEvaluator, selectionStrategy, rng);
        this.adaptableParameters = adaptableParameters;
    }

    public GenerationalAdaptingEvolutionEngine(CandidateFactory<T> tCandidateFactory,
                                               EvolutionaryOperator<T> evolutionScheme,
                                               InteractiveSelection<T> selectionStrategy,
                                               Random rng,
                                               List<AdaptableParameter<T>> adaptableParameters) {
        super(tCandidateFactory, evolutionScheme, selectionStrategy, rng);
        this.adaptableParameters = adaptableParameters;
    }

    public void addAdaptableParameter(AdaptableParameter<T> adaptableParameter) {
        adaptableParameters.add(adaptableParameter);
    }

    @Override
    protected List<EvaluatedCandidate<T>> nextEvolutionStep(List<EvaluatedCandidate<T>> evaluatedPopulation,
                                                            int eliteCount,
                                                            Random rng) {
        List<EvaluatedCandidate<T>> nextGeneration = super.nextEvolutionStep(evaluatedPopulation, eliteCount, rng);
        if (lastGenerations.size() > 1) {
            for (AdaptableParameter<T> parameter : adaptableParameters) {
                parameter.adapt(lastGenerations);
            }
        }
        lastGenerations.add(nextGeneration);
        if (lastGenerations.size() > 2) {
            lastGenerations.remove(0);
        }
        return nextGeneration;
    }

}
